package cn.tedu.person.service.impl;

import cn.tedu.person.ex.ServiceException;
import cn.tedu.person.mapper.AdminMapper;
import cn.tedu.person.mapper.AdminRoleMapper;
import cn.tedu.person.pojo.dto.AdminInsertDTO;
import cn.tedu.person.pojo.dto.AdminLoginInfoDTO;
import cn.tedu.person.pojo.dto.AdminUpdateDTO;
import cn.tedu.person.pojo.entity.Admin;
import cn.tedu.person.pojo.entity.AdminRole;
import cn.tedu.person.pojo.vo.AdminIndexVO;
import cn.tedu.person.pojo.vo.AdminStandardVO;
import cn.tedu.person.security.AdminDetails;
import cn.tedu.person.service.IAdminService;
import cn.tedu.person.web.ServiceCode;
import com.alibaba.fastjson.JSON;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.*;


@Slf4j
@Service
public class AdminServiceImpl implements IAdminService {

    @Autowired
    private AdminMapper adminMapper;

    @Autowired
    private AdminRoleMapper adminRoleMapper;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public void addNew(AdminInsertDTO adminInsertDTO) {

        log.debug("开始处理【添加管理员】的业务 参数为：{}",adminInsertDTO);

        //先判断添加的是否为系统管理员 系统管理员只能有一个，不能添加
        Long[] roleIds=adminInsertDTO.getRoleIds();
        for (int i = 0; i < roleIds.length; i++) {
            if(roleIds[i] == 1){
                String message = "添加管理员失败，不可以系统管理员角色";
                log.warn(message);
                throw new ServiceException(ServiceCode.ERR_CONFLICT,message);
            }
        }

        //判断名称
        String name=adminInsertDTO.getName();
        int countByName=adminMapper.countByName(name);
        if(countByName>0){
            String message = "添加管理员失败，名称已经被占用！";
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        //处理添加
        Admin admin=new Admin();
        BeanUtils.copyProperties(adminInsertDTO,admin);
        //处理加密密码 把加密密码放到数据库中
        String rawPassword = admin.getPassword();//原文
        String encodedPassword = passwordEncoder.encode(rawPassword);//密文
        admin.setPassword(encodedPassword);

        int rows=adminMapper.insert(admin);
        if (rows != 1) {
            String message = "添加管理员失败，服务器忙，请稍后再尝试！";
            throw new ServiceException(ServiceCode.ERR_INSERT, message);
        }

        //添加管理员之后，相应的角色表也要添加对应新管理员的角色
        //新添加的管理员可能和之前管理员有相同的多个角色
        List<AdminRole> adminRoleList=new ArrayList<>();
        for (int i = 0; i < roleIds.length; i++) {
            AdminRole adminRole=new AdminRole();
            adminRole.setAdminId(admin.getId());
            adminRole.setRoleId(roleIds[i]);
            adminRoleList.add(adminRole);
        }

        rows = adminRoleMapper.insertBatch(adminRoleList);
        if (rows != adminRoleList.size()) {
            String message = "添加管理员失败，服务器忙，请稍后再尝试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_INSERT, message);
        }
    }

    @Override
    public void deleteById(Long id) {

        log.debug("开始处理【根据id删除管理员】的业务，参数：{}",id);

        //不允许删除1号管理员
        if (id == 1) {
            String message = "删除管理员失败，尝试访问的数据不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        //检查删除的数据是否存在
        AdminStandardVO queryResult = adminMapper.getStandardById(id);
        if(queryResult == null ){
            String message="尝试访问的数据不存在";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND,message);
        }

        //执行删除
        log.debug("即将执行删除数据，参数：{}", id);
        int rows=adminMapper.deleteById(id);
        if (rows != 1) {
            String message = "删除管理员失败，服务器忙，请稍后再尝试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_INSERT, message);
        }

        //执行删除 管理员与角色的关联表
        rows=adminRoleMapper.deleteByAdminId(id);
        if (rows < 1) {
            String message = "删除管理员失败，服务器忙，请稍后再尝试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_DELETE, message);
        }
    }

    @Override
    public List<AdminIndexVO> list() {
        return adminMapper.list();
    }


    @Override
    public AdminStandardVO getStandardById(Long id) {
        AdminStandardVO queryResult = adminMapper.getStandardById(id);
        if(queryResult == null ){
            String message="尝试访问的数据不存在";
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND,message);
        }
        return queryResult;
    }

    @Override
    public String login(AdminLoginInfoDTO adminLoginInfoDTO) {
        log.debug("开始处理【管理员登录】的业务，参数：{}",adminLoginInfoDTO);

        //创建认证对象
        Authentication authentication=new UsernamePasswordAuthenticationToken(
          adminLoginInfoDTO.getName(),adminLoginInfoDTO.getPassword());

        //调用认证管理器执行认证
        Authentication authenticateResult
                = authenticationManager.authenticate(authentication);
        log.debug("认证通过！");
        //将返回的认证信息保存到securityContext中
//        SecurityContext securityContext= SecurityContextHolder.getContext();
//        securityContext.setAuthentication(authenticateResult);

        //处理验证登录成功后的结果当事人
        Object principal =authenticateResult.getPrincipal();
        log.debug("获取验证登录成功后的结果中的当事人：{}",principal);
        AdminDetails adminDetails= (AdminDetails) principal;

        //需要写入到JWT中的数据
        Map<String,Object> claims=new HashMap<>();
        claims.put("id",adminDetails.getId());
        claims.put("name",adminDetails.getUsername());
        //需要再jwt中存入管理员的权限列表
        String authoritiesJsonString = JSON.toJSONString(adminDetails.getAuthorities());
        claims.put("authoritiesJsonString",authoritiesJsonString);
        log.debug("即将生成JWT数据，包含的账号信息{}",claims);

        //生成jwt 并且返回jwt
        String secretKey="kU4jrFA3iuI5jn25u743kfDs7a8pFEwS54hm";
        Date exp=new Date(System.currentTimeMillis()+10*24*60*60*1000);//10天
        String jwt= Jwts.builder()
                .setHeaderParam("alg","HS256")
                .setHeaderParam("typ","JWT")
                .setClaims(claims)
                .setExpiration(exp)
                .signWith(SignatureAlgorithm.HS256,secretKey)
                .compact();
        log.debug("生成了JWT数据，并将返回JWT数据：{}",jwt);
        return jwt;
    }

    @Override
    public void setEnable(Long id) {
        updateEnableById(id,1);
    }

    @Override
    public void setDisable(Long id) {
        updateEnableById(id,0);
    }

    private void updateEnableById(Long id, Integer enable) {
        log.debug("开始处理【{}管理员】的业务,ID:{},目标状态：{}",ENABLE_TEXT[enable],id,enable);

        //1号管理员不能调整
        if(id == 1){
            String message = ENABLE_TEXT[enable] + "管理员失败，尝试访问的数据不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        AdminStandardVO queryResult = adminMapper.getStandardById(id);
        if(queryResult == null ){
            String message=ENABLE_TEXT[enable] + "管理员失败，尝试访问的数据不存在！";
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND,message);
        }

        // 检查当前状态是否与参数表示的状态相同
        if(queryResult.getEnable().equals(enable)){
            String message = ENABLE_TEXT[enable] + "管理员失败，当前管理员已经处于"
                    + ENABLE_TEXT[enable] + "状态！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        Admin admin = new Admin();
        admin.setId(id);
        admin.setEnable(enable);
        log.debug("即将修改数据，参数：{}", admin);
        int rows = adminMapper.update(admin);
        if (rows != 1) {
            String message = ENABLE_TEXT[enable] + "管理员失败，服务器忙，请稍后再次尝试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_UPDATE, message);
        }
    }

}
